/*
 *  Copyright 2010 Alexey Frishman (alexey.frishman@gmail.com)
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not
 *  use this file except in compliance with the License. You may obtain a copy of
 *  the License at
 *  
 *  http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 *  License for the specific language governing permissions and limitations under
 *  the License.
 * 
 */

package org.json4g.serialization;

import static org.json4g.TypeUtil.fakeField;
import static org.json4g.TypeUtil.getClassType;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.json4g.TypeUtil;
import org.json4g.serialization.parameterized.JsonListSerializer;
import org.json4g.serialization.parameterized.JsonMapSerializer;
import org.json4g.serialization.parameterized.JsonSetSerializer;
import org.json4g.serialization.policy.SerializationPolicy;
import org.json4g.serialization.primitive.JsonBooleanSerializer;
import org.json4g.serialization.primitive.JsonByteSerializer;
import org.json4g.serialization.primitive.JsonDoubleSerializer;
import org.json4g.serialization.primitive.JsonFloatSerializer;
import org.json4g.serialization.primitive.JsonIntegerSerializer;
import org.json4g.serialization.primitive.JsonLongSerializer;
import org.json4g.serialization.primitive.JsonShortSerializer;
import org.json4g.serialization.primitive.JsonStringSerializer;

import com.google.gwt.json.client.JSONValue;
import com.gwtent.reflection.client.impl.ClassTypeImpl;

/**
 * Useful facade to the whole JSON Serialization component. This should be the entry point for external users of the API.
 */
public class JsonSerializerFacade {
    private JsonSerializer mainSerializer;
    private JsonListSerializer listSerializer;
    private JsonSetSerializer setSerializer;

    public JsonSerializerFacade(SerializationPolicy policy) {
        initPrimitiveTypes();

        List<JsonSerializer> serializers = new ArrayList<JsonSerializer>();
        mainSerializer = new JsonCompositeSerializer(serializers);

        initPrimitiveSerializers(serializers);
        listSerializer = new JsonListSerializer(mainSerializer, policy);
        serializers.add(listSerializer);
        setSerializer = new JsonSetSerializer(mainSerializer, policy);
        serializers.add(setSerializer);
        serializers.add(new JsonMapSerializer(mainSerializer, policy));
        serializers.add(new JsonBeanSerializer(mainSerializer, policy));
    }

    private static void initPrimitiveTypes() {
        // newly created class types become automatically available from anywhere
        new ClassTypeImpl(Short.class);
        new ClassTypeImpl(Long.class);
        new ClassTypeImpl(Integer.class);
        new ClassTypeImpl(Double.class);
        new ClassTypeImpl(Float.class);
        new ClassTypeImpl(Byte.class);
        new ClassTypeImpl(Boolean.class);
        new ClassTypeImpl(String.class);
    }

    private static void initPrimitiveSerializers(List<JsonSerializer> allSerializers) {
        allSerializers.add(new JsonShortSerializer());
        allSerializers.add(new JsonBooleanSerializer());
        allSerializers.add(new JsonByteSerializer());
        allSerializers.add(new JsonDoubleSerializer());
        allSerializers.add(new JsonLongSerializer());
        allSerializers.add(new JsonIntegerSerializer());
        allSerializers.add(new JsonStringSerializer());
        allSerializers.add(new JsonFloatSerializer());
    }

    public JSONValue serialize(Object object) {
        return mainSerializer.serialize(object);
    }

    @SuppressWarnings("unchecked")
    public <E> E deserialize(JSONValue json, Class<E> clazz) {
        Object result = mainSerializer.deserialize(json, fakeField(getClassType(clazz)));
        return (E) result;
    }
    
    @SuppressWarnings("unchecked")
    public <E> List<E> deserializeList(JSONValue json, Class<E> itemClass) {
        return (List<E>) listSerializer.deserialize(json, TypeUtil.getClassType(itemClass));
    }
    
    @SuppressWarnings("unchecked")
    public <E> Set<E> deserializeSet(JSONValue json, Class<E> itemClass) {
        return (Set<E>) setSerializer.deserialize(json, TypeUtil.getClassType(itemClass));
    }
}
